package systemfnomabss;

trait TextualSyntax { 
 

  type RawTerm = RTerm
  type RawType = RType

 sealed abstract class RTerm {}




 trait RBaseValue extends RTerm {
   def baseType():RBaseType
 }


  case class RTru extends RTerm with RBaseValue{
    override def toString = "true"
    override def baseType = RTyBool()
  }
  case class RFls extends RTerm with RBaseValue{
    override def toString= "false"
    override def baseType = RTyBool()
  }
  case class RUnit extends RTerm with RBaseValue{
    override def toString = "unit"
    override def baseType = RTyUnit()
  }
  case class RLit(n: int) extends RTerm with RBaseValue{
    override def toString = n.toString
    override def baseType = RTyInt()
  }
  
  
  case class RIf(cond: RTerm, pos: RTerm, neg: RTerm) extends RTerm {

  }
 
  case class RVarName(n: String) extends RTerm {
    override def toString = n
  }

  
  

  //case class RVar(n: RVarName) extends RTerm  {
  //}
  
  case class RLam(x: RVarName, ty: RType, t:RTerm) extends RTerm {
  }
  
  case class RApp(t1:RTerm, t2:RTerm) extends RTerm {
  }
  case class RLet(n: RVarName, t1: RTerm, t2: RTerm) extends RTerm {
    override def toString = "let "+n+" = "+t1+" in "+t2
  }
  
  //TVar -> see TyVar
  case class RTLam(hint: RTyVarName, t:RTerm) extends RTerm {
  }
    

  case class RTApp(t1:RawTerm, ty: RawType) extends RTerm {
  }
  case class RPack(ty:RawType, t:RawTerm, pubty:RawType) extends RTerm {
  }
  
  case class RUnpack(impl: RawTerm, pubty:RTyVarName,pubvar:RVarName, body:RawTerm) extends RTerm {
  }
  
  case class RRecord(fields: List[(String,RTerm)]) extends RTerm {
    override def toString = "{" + fields.foldRight("")({case ((s,t),xs) => s +"="+ t +", "+ xs} )+ "}"
    def map[R](f:RTerm=>R):List[(String,R)] =
      fields.map({case (label,fld)=> (label,f(fld))})
  }
  case class RRecProj(t: RTerm, label: String) extends RTerm {
    
  }



  sealed trait RType extends RTerm 
  
  trait RBaseType extends RType {
    val name: String
    override def toString = name
  }
  
  case class RTyBool() extends RType with RBaseType
  { val name="Bool" }
  case class RTyInt()  extends RType with RBaseType
  { val name="Int"  }
  case class RTyTop()  extends RType with RBaseType
  { val name="Top"  }
  case class RTyUnit() extends RType with RBaseType
  { val name="Unit" }

  case class RTyVarName(n: String) extends RType {
    //override def toString = n
  }
  case class RTyArr(t1: RType, t2: RType) extends RType {
    //override def toString = "("+t1 +" => " +t2+")"
    def map(f:RType=>RType):RTyArr=
       RTyArr(f(t1), f(t2))
  }
  case class RTyUniv(x: RTyVarName, ty: RType) extends RType  {
    //override def toString = "forall "+x +". "+ty
  }
  case class RTyExist(x:RTyVarName, ty: RType) extends RType {
    //override def toString = "{forsome "+x+","+ty+"}"
  }

  case class RTyRecord(fields: List[(String,RType)]) extends RType {
    def map[R](f:RType=>R):List[(String,R)] =
        fields.map({case (label,fld)=> (label,f(fld))})
    def field(label:String) = {
        val results = fields.filter( {case (fldlabel,fldtype) => label == fldlabel}).map(_ _2)
        if (results.length == 0)throw new TypeExc("no label "+label+" in record")
        if (results.length >1  )throw new TypeExc("multiple labels "+label+" in record")
        results.head
    }
  }
  
}

